
#include "Dream3DRender.h"
#include <vsgQt/Window.h>

#include "vsgUI.h"
#include <qmenubar.h>
#include <qstatusbar.h>
#include <vsgQt/Window.h>

#define STB_IMAGE_IMPLEMENTATION
#include "CornerGrid.h"
#include "ProgressDlg.h"
#include "stb_image.h"
#include "stb_image_write.h"
#include "vsgUI.h"
#include <iostream>

template <class T>
class PipelineBindVisitor : public vsg::Inherit<vsg::Visitor, PipelineBindVisitor<T>>
{
public:
  PipelineBindVisitor(vsg::ref_ptr<T> pipelineBind) : mPipelineState(pipelineBind) {}
  virtual void apply(vsg::StateGroup& stateGroup) override
  {
    if (!stateGroup.contains(mPipelineState))
    {
      stateGroup.add(mPipelineState);
    }
  }
  vsg::ref_ptr<T> mPipelineState;
};

ScenePick::ScenePick(vsgUI* uiWindow, vsg::ref_ptr<vsg::Camera> camera, vsg::ref_ptr<vsg::Camera> pickcamera, vsg::ref_ptr<vsg::Viewer> viewer,
                     vsg::ref_ptr<vsg::Device> device, vsg::ref_ptr<vsg::Image> captureIJKImage, vsg::ref_ptr<vsg::Image> locationImage)
{
  mUIWindow = uiWindow;
  mCamera   = camera;
  mLookAt   = mCamera->viewMatrix.cast<vsg::LookAt>();

  mPickCamera = pickcamera;
  mpickLookAt = mPickCamera->viewMatrix.cast<vsg::LookAt>();

  mViewer   = viewer;
  mDevice   = device;
  mIJKImage = captureIJKImage;
  mWidth    = captureIJKImage->extent.width;
  mHeight   = captureIJKImage->extent.height;

  mLocationImage = locationImage;
}

void ScenePick::apply(vsg::ButtonPressEvent& buttonPress)
{
  // std::cout << "Button Event: " << buttonPress.button << std::endl;
  // std::cout << "(x,y):"
  //           << "(" << buttonPress.x << "," << buttonPress.y << ")" << std::endl;

  // vsg::Path captureFilename = "captureFilename.vsgt";
  // auto options = vsg::Options::create();
  // saveImage(captureFilename, mViewer, mDevice, mColorImage, options);
  // return;
  // debug
  // auto imageData      = getImageData(mViewer, mDevice, mIJKImage);
  // int channels        = 4;  // RGB
  // unsigned char* data = new unsigned char[mWidth * mHeight * channels];
  // long id             = 0;
  // vsg::vec4* pdata    = (vsg::vec4*)(imageData->dataPointer());
  // for (int y = 0; y < mHeight; ++y)
  //{
  //  for (int i = 0; i < mWidth; i++)
  //  {
  //    data[4 * id]     = 255 * pdata[id].r;
  //    data[4 * id + 1] = 255 * pdata[id].g;
  //    data[4 * id + 2] = 255 * pdata[id].b;
  //    data[4 * id + 3] = 255;
  //    id++;
  //  }
  //}
  // stbi_write_bmp("output.bmp", mWidth, mHeight, channels, data);
  // delete[] data;
  if (mUIWindow->GetPick())
  {
    CalcPickID(buttonPress.x, buttonPress.y, mPickID, mPickLocation);
    if (mUIWindow)
    {
      vsg::dmat4 inverseViewMatrix = vsg::inverse(mLookAt->transform());
      vsg::dvec4 world             = inverseViewMatrix * vsg::dvec4(mPickLocation.x, mPickLocation.y, mPickLocation.z, 1);
      mUIWindow->ShowPickMessage(mPickID, vsg::dvec3(world.x, world.y, world.z));
    }
  }
}
void ScenePick::apply(vsg::MoveEvent& event)
{
  VkViewport vkViewPort = mCamera->getViewport();
  vsg::dvec3 center;
  vsg::dvec3 dir;
  dir                 = vsg::normalize(mLookAt->center - mLookAt->eye);
  double NearDistance = 1;
  double Asp          = (1.0 * vkViewPort.width) / vkViewPort.height;
  center              = mLookAt->center;
  double rad          = 90 * vsg::PI / 180.0;

  double halfH = tan(0.5 * rad) * NearDistance;
  double halfW = Asp * halfH;

  double mRatioX = 2.0 * halfW / vkViewPort.width;
  double mRatioY = 2.0 * halfH / vkViewPort.height;

  vsg::dvec3 mRight = vsg::cross(dir, mLookAt->up);
  mRight            = vsg::normalize(mRight);
  vsg::dvec3 mUp    = vsg::normalize(vsg::cross(mRight, dir));

  vsg::dvec3 clipCenter = mLookAt->eye + dir * NearDistance;

  double xOffset  = (event.x - 0.5f * vkViewPort.width) * mRatioX;
  double upOffset = (0.5f * vkViewPort.height - event.y) * mRatioY;

  vsg::dvec3 ret  = clipCenter + mRight * xOffset + mUp * upOffset;
  vsg::dvec3 dir0 = ret - mLookAt->eye;
  dir0            = vsg::normalize(dir0);

  mpickLookAt->eye        = mLookAt->eye;
  mpickLookAt->center     = mLookAt->eye + dir0 * 20.0;
  mpickLookAt->up         = mLookAt->up;
  mPickCamera->viewMatrix = mpickLookAt;
}
vsg::ref_ptr<vsg::Data> ScenePick::getImageData(vsg::ref_ptr<vsg::Viewer> viewer, vsg::ref_ptr<vsg::Device> device,
                                                vsg::ref_ptr<vsg::Image> captureImage)
{

  VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };

  vkGetImageSubresourceLayout(*device, captureImage->vk(device->deviceID), &subResource, &mSubResourceLayout);

  auto deviceMemory = captureImage->getDeviceMemory(device->deviceID);

  int sizeVec4        = sizeof(vsg::vec4);
  size_t destRowWidth = captureImage->extent.width * sizeVec4;
  vsg::ref_ptr<vsg::Data> imageData;
  if (destRowWidth == mSubResourceLayout.rowPitch)
  {
    imageData = vsg::MappedData<vsg::vec4Array2D>::create(deviceMemory, mSubResourceLayout.offset, 0, vsg::Data::Properties{ captureImage->format },
                                                          captureImage->extent.width, captureImage->extent.height);
  }
  else
  {
    /// Map the buffer memory and assign as a ubyteArray that will automatically
    /// unmap itself on destruction. A ubyteArray is used as the graphics buffer
    /// memory is not contiguous like vsg::Array2D, so map to a flat buffer first
    /// then copy to Array2D.
    auto mappedData =
      vsg::MappedData<vsg::ubyteArray>::create(deviceMemory, mSubResourceLayout.offset, 0, vsg::Data::Properties{ captureImage->format },
                                               mSubResourceLayout.rowPitch * captureImage->extent.height);
    imageData = vsg::vec4Array2D::create(captureImage->extent.width, captureImage->extent.height, vsg::Data::Properties{ captureImage->format });
    for (uint32_t row = 0; row < captureImage->extent.height; ++row)
    {
      std::memcpy(imageData->dataPointer(row * captureImage->extent.width), mappedData->dataPointer(row * mSubResourceLayout.rowPitch), destRowWidth);
    }
  }
  return imageData;
}
void ScenePick::saveImage(vsg::Path const& filename, vsg::ref_ptr<vsg::Viewer> viewer, vsg::ref_ptr<vsg::Device> device,
                          vsg::ref_ptr<vsg::Image> captureImage, vsg::ref_ptr<vsg::Options> options)
{
  vsg::info("writing image to file: ", filename);
  auto imageData = getImageData(viewer, device, captureImage);
  vsg::write(imageData, filename, options);
  vsg::info("image saved.");
}

void ScenePick::CalcPickID(int x, int y, vsg::ivec3& outPickID, vsg::vec3& outLocation)
{
  constexpr uint64_t waitTimeout = 1000000;  // 1 second
  mViewer->waitForFences(0, waitTimeout);

  auto imageDataIJK      = getImageData(mViewer, mDevice, mIJKImage);
  auto imageDataLocation = getImageData(mViewer, mDevice, mLocationImage);
  int size               = imageDataIJK->valueCount();
  // int pickID             = x + y * mWidth;
  int pickID = 0.5 * mWidth + mWidth * 0.5 * mHeight;
  if (pickID < size)
  {
    vsg::vec4* pdata     = (vsg::vec4*)(imageDataIJK->dataPointer());
    vsg::vec4* pLocation = (vsg::vec4*)(imageDataLocation->dataPointer());
    if (pdata)
    {
      outPickID = vsg::ivec3(pdata[pickID].x + 0.5f, pdata[pickID].y + 0.5f, pdata[pickID].z + 0.5f);
    }
    if (pLocation)
    {
      outLocation = vsg::vec3(pLocation[pickID].x, pLocation[pickID].y, pLocation[pickID].z);
    }
  }
  else
  {
  }
}

vsg::ref_ptr<vsg::ubvec4Array2D> updateBaseTexture(std::string path, vsg::ref_ptr<vsg::ubvec4Array2D>& needUpdate, bool bupdate, float value)
{
  int texWidth = 0, texHeight = 0, texChannels = 0;
  stbi_uc* pixels                         = nullptr;
  VkDeviceSize imageSize                  = texWidth * texHeight * 4;
  vsg::ref_ptr<vsg::ubvec4Array2D> buffer = nullptr;
  pixels                                  = stbi_load(path.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
  if (pixels == nullptr)
  {
    return nullptr;
  }
  if (!bupdate)
  {
    buffer                          = vsg::ubvec4Array2D::create(texWidth, texHeight);
    buffer->properties.dataVariance = vsg::DYNAMIC_DATA;
    buffer->properties.format       = VK_FORMAT_R8G8B8A8_UNORM;
    imageSize                       = texWidth * texHeight * 4;
  }
  else
  {
    if (needUpdate)
    {
      texWidth  = needUpdate->width();
      texHeight = needUpdate->height();
    }
  }
  int index = 0;
  for (uint32_t r = 0; r < texHeight; ++r)
  {
    for (uint32_t c = 0; c < texWidth; ++c)
    {
      unsigned char* pixelOffset = pixels + (c + r * texWidth) * 4;
      unsigned char rr           = pixelOffset[0];
      unsigned char gg           = pixelOffset[1];
      unsigned char bb           = pixelOffset[2];
      index++;
      if (bupdate && needUpdate)
      {
        needUpdate->set(c, r, vsg::ubvec4(rr, gg, bb, 255));
      }
      else
      {
        buffer->set(c, r, vsg::ubvec4(rr, gg, bb, 255));
      }
      // float c_ratio = static_cast<float>(c) / static_cast<float>(buffer->width() - 1);
      // vsg::vec2 delta((r_ratio - 0.5f), (c_ratio - 0.5f));
      // float angle = atan2(delta.x, delta.y);
      // float distance_from_center = vsg::length(delta);
      // float intensity = (sin(1.0f * angle + 30.0f * distance_from_center + 10.0f * value) + 1.0f) * 0.5f;
      // buffer->set(c, r, vsg::ubvec4(uint8_t(intensity * intensity * 255.0f), uint8_t(intensity * 255.0f), uint8_t(intensity * 255.0f), 255));
    }
  }
  // image.dirty();
  if (bupdate && needUpdate)
  {
    needUpdate->dirty();
  }
  if (buffer)
  {
    buffer->dirty();
  }

  stbi_image_free(pixels);
  return buffer;
}

void updateElevation(vsg::floatArray2D& heightField, float value)
{
  for (uint32_t r = 0; r < heightField.height(); ++r)
  {
    float r_ratio = static_cast<float>(r) / static_cast<float>(heightField.height() - 1);
    for (uint32_t c = 0; c < heightField.width(); ++c)
    {
      float c_ratio = static_cast<float>(c) / static_cast<float>(heightField.width() - 1);

      vsg::vec2 delta((r_ratio - 0.5f), (c_ratio - 0.5f));

      float angle = atan2(delta.x, delta.y);

      float distance_from_center = vsg::length(delta);

      float intensity = (sin(1.0f * angle + 10.0f * distance_from_center + 2.0f * value) + 1.0f) * 0.5f;
      heightField.set(c, r, intensity);
    }
  }
  heightField.dirty();
}

vsg::ref_ptr<vsg::Node> createGeometry()
{
  // set up vertex and index arrays
  auto vertices = vsg::vec3Array::create(
    { { -0.5f, 0.0f, -0.5f },
      { 0.5f, 0.0f, -0.5f },
      { 0.5f, 0.0f, 0.5f },
      { -0.5f, 0.0f,
        0.5f } });  // VK_FORMAT_R32G32B32_SFLOAT, VK_VERTEX_INPUT_RATE_INSTANCE, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE

  auto colors = vsg::vec3Array::create(vertices->size(), vsg::vec3(1.0f, 1.0f, 1.0f));

  auto texcoords = vsg::vec2Array::create(
    { { 0.0f, 0.0f },
      { 1.0f, 0.0f },
      { 1.0f, 1.0f },
      { 0.0f, 1.0f } });  // VK_FORMAT_R32G32_SFLOAT, VK_VERTEX_INPUT_RATE_VERTEX, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE

  auto indices = vsg::ushortArray::create({ 0, 1, 2, 2, 3, 0 });  // VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE

  auto vid = vsg::VertexIndexDraw::create();
  vid->assignArrays(vsg::DataList{ vertices, colors, texcoords });
  vid->assignIndices(indices);
  vid->indexCount    = 6;
  vid->instanceCount = 1;
  return vid;
}

bool supportsBlit(vsg::ref_ptr<vsg::Device> device, VkFormat format)
{
  auto physicalDevice = device->getPhysicalDevice();
  VkFormatProperties srcFormatProperties;
  vkGetPhysicalDeviceFormatProperties(*(physicalDevice), format, &srcFormatProperties);
  VkFormatProperties destFormatProperties;
  vkGetPhysicalDeviceFormatProperties(*(physicalDevice), VK_FORMAT_R8G8B8A8_UNORM, &destFormatProperties);
  return ((srcFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) != 0)
         && ((destFormatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) != 0);
}

vsg::ref_ptr<vsg::Image> createCaptureImage(vsg::ref_ptr<vsg::Device> device, VkFormat sourceFormat, const VkExtent2D& extent)
{
  // blit to RGBA if supported
  // auto targetFormat = supportsBlit(device, sourceFormat) ? VK_FORMAT_R8G8B8A8_UNORM : sourceFormat;
  //
  // create image to write to
  auto image         = vsg::Image::create();
  image->format      = sourceFormat /*targetFormat*/;
  image->extent      = { extent.width, extent.height, 1 };
  image->arrayLayers = 1;
  image->mipLevels   = 1;
  image->tiling      = VK_IMAGE_TILING_LINEAR;
  image->usage       = VK_IMAGE_USAGE_TRANSFER_DST_BIT;

  image->compile(device);

  auto memReqs      = image->getMemoryRequirements(device->deviceID);
  auto memFlags     = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  auto deviceMemory = vsg::DeviceMemory::create(device, memReqs, memFlags);
  image->bind(deviceMemory, 0);

  return image;
}

VkImageUsageFlags computeUsageFlagsForFormat(VkFormat format)
{
  switch (format)
  {
  case VK_FORMAT_D16_UNORM_S8_UINT:
  case VK_FORMAT_D24_UNORM_S8_UINT:
  case VK_FORMAT_D32_SFLOAT_S8_UINT:
  case VK_FORMAT_D16_UNORM:
  case VK_FORMAT_D32_SFLOAT:
  case VK_FORMAT_X8_D24_UNORM_PACK32:
    return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  default:
    return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  }
}

vsg::ref_ptr<vsg::ImageView> createTransferImageView(vsg::ref_ptr<vsg::Device> device, VkFormat format, const VkExtent2D& extent,
                                                     VkSampleCountFlagBits samples)
{
  auto image         = vsg::Image::create();
  image->format      = format;
  image->extent      = VkExtent3D{ extent.width, extent.height, 1 };
  image->mipLevels   = 1;
  image->arrayLayers = 1;
  image->samples     = samples;
  image->usage       = computeUsageFlagsForFormat(format) | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  return vsg::createImageView(device, image, vsg::computeAspectFlagsForFormat(format));
}

vsg::ref_ptr<vsg::Commands> createTransferCommands(vsg::ref_ptr<vsg::Device> device, vsg::ref_ptr<vsg::Image> sourceImage,
                                                   vsg::ref_ptr<vsg::Image> destinationImage)
{
  auto commands = vsg::Commands::create();

  // transition destinationImage to transfer destination initialLayout
  auto transitionDestinationImageToDestinationLayoutBarrier =
    vsg::ImageMemoryBarrier::create(0,                                                                // srcAccessMask
                                    VK_ACCESS_TRANSFER_WRITE_BIT,                                     // dstAccessMask
                                    VK_IMAGE_LAYOUT_UNDEFINED,                                        // oldLayout
                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,                             // newLayout
                                    VK_QUEUE_FAMILY_IGNORED,                                          // srcQueueFamilyIndex
                                    VK_QUEUE_FAMILY_IGNORED,                                          // dstQueueFamilyIndex
                                    destinationImage,                                                 // image
                                    VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
    );

  auto cmd_transitionForTransferBarrier = vsg::PipelineBarrier::create(VK_PIPELINE_STAGE_TRANSFER_BIT,                       // srcStageMask
                                                                       VK_PIPELINE_STAGE_TRANSFER_BIT,                       // dstStageMask
                                                                       0,                                                    // dependencyFlags
                                                                       transitionDestinationImageToDestinationLayoutBarrier  // barrier
  );

  commands->addChild(cmd_transitionForTransferBarrier);

  if (sourceImage->format == destinationImage->format && sourceImage->extent.width == destinationImage->extent.width
      && sourceImage->extent.height == destinationImage->extent.height)
  {
    // use vkCmdCopyImage
    VkImageCopy region{};
    region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    region.srcSubresource.layerCount = 1;
    region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    region.dstSubresource.layerCount = 1;
    region.extent                    = destinationImage->extent;

    auto copyImage            = vsg::CopyImage::create();
    copyImage->srcImage       = sourceImage;
    copyImage->srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
    copyImage->dstImage       = destinationImage;
    copyImage->dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    copyImage->regions.push_back(region);

    commands->addChild(copyImage);
  }
  else if (supportsBlit(device, destinationImage->format))
  {
    // blit using vkCmdBlitImage
    VkImageBlit region{};
    region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    region.srcSubresource.layerCount = 1;
    region.srcOffsets[0]             = VkOffset3D{ 0, 0, 0 };
    region.srcOffsets[1] = VkOffset3D{ static_cast<int32_t>(sourceImage->extent.width), static_cast<int32_t>(sourceImage->extent.height), 1 };
    region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    region.dstSubresource.layerCount = 1;
    region.dstOffsets[0]             = VkOffset3D{ 0, 0, 0 };
    region.dstOffsets[1] =
      VkOffset3D{ static_cast<int32_t>(destinationImage->extent.width), static_cast<int32_t>(destinationImage->extent.height), 1 };

    auto blitImage            = vsg::BlitImage::create();
    blitImage->srcImage       = sourceImage;
    blitImage->srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
    blitImage->dstImage       = destinationImage;
    blitImage->dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    blitImage->regions.push_back(region);
    blitImage->filter = VK_FILTER_NEAREST;

    commands->addChild(blitImage);
  }
  else
  {
    /// If the source and target extents and/or format are different
    /// we would need to blit, however this device does not support it.
    /// Options at this point include resizing or reformatting on the
    /// CPU (using STBI for example) or using a sampler and rendering to
    /// a texture in an additional pass.
    throw std::runtime_error{ "GPU does not support blit." };
  }

  // transition destination image from transfer destination layout
  // to general layout to enable mapping to image DeviceMemory
  auto transitionDestinationImageToMemoryReadBarrier =
    vsg::ImageMemoryBarrier::create(VK_ACCESS_TRANSFER_WRITE_BIT,                                     // srcAccessMask
                                    VK_ACCESS_MEMORY_READ_BIT,                                        // dstAccessMask
                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,                             // oldLayout
                                    VK_IMAGE_LAYOUT_GENERAL,                                          // newLayout
                                    VK_QUEUE_FAMILY_IGNORED,                                          // srcQueueFamilyIndex
                                    VK_QUEUE_FAMILY_IGNORED,                                          // dstQueueFamilyIndex
                                    destinationImage,                                                 // image
                                    VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
    );

  auto cmd_transitionFromTransferBarrier = vsg::PipelineBarrier::create(VK_PIPELINE_STAGE_TRANSFER_BIT,                // srcStageMask
                                                                        VK_PIPELINE_STAGE_TRANSFER_BIT,                // dstStageMask
                                                                        0,                                             // dependencyFlags
                                                                        transitionDestinationImageToMemoryReadBarrier  // barrier
  );

  commands->addChild(cmd_transitionFromTransferBarrier);

  return commands;
}

vsg::ref_ptr<vsg::RenderGraph> createOffscreenRendergraph(vsg::Context& context, const VkExtent2D& extent, vsg::ImageInfo& colorImageInfo,
                                                          vsg::ImageInfo& locationImageInfo, vsg::ImageInfo& depthImageInfo, VkFormat format)
{
  auto device = context.device;

  VkExtent3D attachmentExtent{ extent.width, extent.height, 1 };
  // Attachments
  // create image for color attachment
  auto colorImage         = vsg::Image::create();
  colorImage->imageType   = VK_IMAGE_TYPE_2D;
  colorImage->format      = format /*VK_FORMAT_R32G32B32A32_SFLOAT*/ /*VK_FORMAT_R8G8B8A8_UNORM*/;
  colorImage->extent      = attachmentExtent;
  colorImage->mipLevels   = 1;
  colorImage->arrayLayers = 1;

  // colorImage->tiling = VK_IMAGE_TILING_LINEAR;
  // colorImage->usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;

  colorImage->tiling = VK_IMAGE_TILING_OPTIMAL;
  colorImage->usage  = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

  colorImage->samples       = VK_SAMPLE_COUNT_1_BIT;
  colorImage->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  colorImage->flags         = 0;
  colorImage->sharingMode   = VK_SHARING_MODE_EXCLUSIVE;

  auto colorImageView = createImageView(context, colorImage, VK_IMAGE_ASPECT_COLOR_BIT);

  // colorImage->compile(device);
  //// get memory requirements
  // VkMemoryRequirements memRequirements = colorImage->getMemoryRequirements(device->deviceID);
  // auto memFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  //// allocate memory with out export memory info extension
  // auto [deviceMemory, offset] = context.deviceMemoryBufferPools->reserveMemory(memRequirements, memFlags);
  // colorImage->bind(deviceMemory, offset);
  // auto colorImageView = vsg::ImageView::create(colorImage, VK_IMAGE_ASPECT_COLOR_BIT);
  // colorImageView->compile(device);

  // Sampler for accessing attachment as a texture
  auto colorSampler           = vsg::Sampler::create();
  colorSampler->flags         = 0;
  colorSampler->magFilter     = VK_FILTER_LINEAR;
  colorSampler->minFilter     = VK_FILTER_LINEAR;
  colorSampler->mipmapMode    = VK_SAMPLER_MIPMAP_MODE_LINEAR;
  colorSampler->addressModeU  = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
  colorSampler->addressModeV  = colorSampler->addressModeU;
  colorSampler->addressModeW  = colorSampler->addressModeU;
  colorSampler->mipLodBias    = 0.0f;
  colorSampler->maxAnisotropy = 1.0f;
  colorSampler->minLod        = 0.0f;
  colorSampler->maxLod        = 1.0f;
  colorSampler->borderColor   = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;

  colorImageInfo.imageView   = colorImageView;
  colorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  colorImageInfo.sampler     = colorSampler;

  {
    auto colorImage2         = vsg::Image::create();
    colorImage2->imageType   = VK_IMAGE_TYPE_2D;
    colorImage2->format      = format /*VK_FORMAT_R32G32B32A32_SFLOAT*/ /*VK_FORMAT_R8G8B8A8_UNORM*/;
    colorImage2->extent      = attachmentExtent;
    colorImage2->mipLevels   = 1;
    colorImage2->arrayLayers = 1;

    // colorImage->tiling = VK_IMAGE_TILING_LINEAR;
    // colorImage->usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;

    colorImage2->tiling = VK_IMAGE_TILING_OPTIMAL;
    colorImage2->usage  = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

    colorImage2->samples       = VK_SAMPLE_COUNT_1_BIT;
    colorImage2->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorImage2->flags         = 0;
    colorImage2->sharingMode   = VK_SHARING_MODE_EXCLUSIVE;

    auto colorImageView2 = createImageView(context, colorImage2, VK_IMAGE_ASPECT_COLOR_BIT);

    auto colorSampler2           = vsg::Sampler::create();
    colorSampler2->flags         = 0;
    colorSampler2->magFilter     = VK_FILTER_LINEAR;
    colorSampler2->minFilter     = VK_FILTER_LINEAR;
    colorSampler2->mipmapMode    = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    colorSampler2->addressModeU  = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
    colorSampler2->addressModeV  = colorSampler->addressModeU;
    colorSampler2->addressModeW  = colorSampler->addressModeU;
    colorSampler2->mipLodBias    = 0.0f;
    colorSampler2->maxAnisotropy = 1.0f;
    colorSampler2->minLod        = 0.0f;
    colorSampler2->maxLod        = 1.0f;
    colorSampler2->borderColor   = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;

    locationImageInfo.imageView   = colorImageView2;
    locationImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    locationImageInfo.sampler     = colorSampler2;
  }

  // create depth buffer
  VkFormat depthFormat      = VK_FORMAT_D32_SFLOAT;
  auto depthImage           = vsg::Image::create();
  depthImage->imageType     = VK_IMAGE_TYPE_2D;
  depthImage->extent        = attachmentExtent;
  depthImage->mipLevels     = 1;
  depthImage->arrayLayers   = 1;
  depthImage->samples       = VK_SAMPLE_COUNT_1_BIT;
  depthImage->format        = depthFormat;
  depthImage->tiling        = VK_IMAGE_TILING_OPTIMAL;
  depthImage->usage         = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  depthImage->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  depthImage->flags         = 0;
  depthImage->sharingMode   = VK_SHARING_MODE_EXCLUSIVE;

  // XXX Does layout matter?
  depthImageInfo.sampler     = nullptr;
  depthImageInfo.imageView   = vsg::createImageView(context, depthImage, VK_IMAGE_ASPECT_DEPTH_BIT);
  depthImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;

  // attachment descriptions
  vsg::RenderPass::Attachments attachments(3);
  // Color attachment
  attachments[0].format         = VK_FORMAT_R8G8B8A8_UNORM;
  attachments[0].samples        = VK_SAMPLE_COUNT_1_BIT;
  attachments[0].loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
  attachments[0].storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
  attachments[0].stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  attachments[0].initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
  attachments[0].finalLayout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

  attachments[1].format         = VK_FORMAT_R8G8B8A8_UNORM;
  attachments[1].samples        = VK_SAMPLE_COUNT_1_BIT;
  attachments[1].loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
  attachments[1].storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
  attachments[1].stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  attachments[1].initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
  attachments[1].finalLayout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

  // Depth attachment
  attachments[2].format         = depthFormat;
  attachments[2].samples        = VK_SAMPLE_COUNT_1_BIT;
  attachments[2].loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
  attachments[2].storeOp        = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  attachments[2].stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  attachments[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  attachments[2].initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
  attachments[2].finalLayout    = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

  vsg::AttachmentReference colorReference  = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
  vsg::AttachmentReference colorReference2 = { 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
  vsg::AttachmentReference depthReference  = { 2, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };

  vsg::RenderPass::Subpasses subpassDescription(1);
  subpassDescription[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  subpassDescription[0].colorAttachments.emplace_back(colorReference);
  subpassDescription[0].colorAttachments.emplace_back(colorReference2);
  subpassDescription[0].depthStencilAttachments.emplace_back(depthReference);

  vsg::RenderPass::Dependencies dependencies(3);

  // XXX This dependency is copied from the offscreenrender.cpp
  // example. I don't completely understand it, but I think its
  // purpose is to create a barrier if some earlier render pass was
  // using this framebuffer's attachment as a texture.
  dependencies[0].srcSubpass      = VK_SUBPASS_EXTERNAL;
  dependencies[0].dstSubpass      = 0;
  dependencies[0].srcStageMask    = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  dependencies[0].dstStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[0].srcAccessMask   = VK_ACCESS_SHADER_READ_BIT;
  dependencies[0].dstAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

  dependencies[1].srcSubpass      = VK_SUBPASS_EXTERNAL;
  dependencies[1].dstSubpass      = 0;
  dependencies[1].srcStageMask    = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  dependencies[1].dstStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[1].srcAccessMask   = VK_ACCESS_SHADER_READ_BIT;
  dependencies[1].dstAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

  // This is the heart of what makes Vulkan offscreen rendering
  // work: render passes that follow are blocked from using this
  // passes' color attachment in their fragment shaders until all
  // this pass' color writes are finished.
  dependencies[2].srcSubpass      = 0;
  dependencies[2].dstSubpass      = VK_SUBPASS_EXTERNAL;
  dependencies[2].srcStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[2].dstStageMask    = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  dependencies[2].srcAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  dependencies[2].dstAccessMask   = VK_ACCESS_SHADER_READ_BIT;
  dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

  auto renderPass = vsg::RenderPass::create(device, attachments, subpassDescription, dependencies);

  // Framebuffer
  auto fbuf = vsg::Framebuffer::create(renderPass, vsg::ImageViews{ colorImageInfo.imageView, locationImageInfo.imageView, depthImageInfo.imageView },
                                       extent.width, extent.height, 1);

  auto rendergraph               = vsg::RenderGraph::create();
  rendergraph->renderArea.offset = VkOffset2D{ 0, 0 };
  rendergraph->renderArea.extent = extent;
  rendergraph->framebuffer       = fbuf;

  rendergraph->clearValues.resize(3);
  rendergraph->clearValues[0].color        = { { -2.0f, -2.0f, -2.0f, -2.0f } };
  rendergraph->clearValues[1].color        = { { 0.0f, 0.0f, 0.0f, 1.0f } };
  rendergraph->clearValues[2].depthStencil = VkClearDepthStencilValue{ 0.0f, 0 };

  return rendergraph;
}

vsg::ref_ptr<vsg::Node> createGeometry(uint32_t numColumns, uint32_t numRows)
{
  uint32_t numVertices = numColumns * numRows;
  float width          = 1.0;
  float height         = 1.0;

  // set up vertex and index arrays
  auto vertices  = vsg::vec3Array::create(numVertices);
  auto texcoords = vsg::vec4Array::create(numVertices);
  auto normals   = vsg::vec3Array::create(numVertices, vsg::vec3(0.0f, 0.0f, 1.0f));
  auto ijks      = vsg::vec3Array::create(numVertices, vsg::vec3(-1.0f, -1.0f, -1.0f));

  vsg::vec3 vertex_origin(0.0f, 0.0f, 0.0f);
  vsg::vec3 vertex_dx(width / (static_cast<float>(numColumns) - 1.0f), 0.0f, 0.0f);
  vsg::vec3 vertex_dy(0.0f, height / (static_cast<float>(numRows) - 1.0f), 0.0f);

  vsg::vec4 texcoord_origin(0.0f, 0.0f, 0, 0);
  vsg::vec4 texcoord_dx(1.0f / (static_cast<float>(numColumns) - 1.0f), 0.0f, 0, 0);
  vsg::vec4 texcoord_dy(0.0f, 1.0f / (static_cast<float>(numRows) - 1.0f), 0, 0);

  auto vertex_itr   = vertices->begin();
  auto texcoord_itr = texcoords->begin();
  auto normal_itr   = normals->begin();

  auto ijk_itr = ijks->begin();

  for (uint32_t r = 0; r < numRows; ++r)
  {
    for (uint32_t c = 0; c < numColumns; ++c)
    {
      *(vertex_itr++)   = vertex_origin + vertex_dx * (static_cast<float>(c)) + vertex_dy * (static_cast<float>(r));
      *(texcoord_itr++) = texcoord_origin + texcoord_dx * (static_cast<float>(c)) + texcoord_dy * (static_cast<float>(r));
      *(normal_itr++)   = vsg::vec3(0, 0, 1);
      *(ijk_itr++)      = vsg::vec3(100, 200, 300);
    }
  }

  uint32_t numIndices = (numColumns - 1) * (numRows - 1) * 6;
  auto indices        = vsg::ushortArray::create(numIndices);
  auto itr            = indices->begin();
  for (uint32_t r = 0; r < (numRows - 1); ++r)
  {
    for (uint32_t c = 0; c < (numColumns - 1); ++c)
    {
      uint32_t i = r * numColumns + c;
      // lower left triangle
      *(itr++) = i;
      *(itr++) = i + 1;
      *(itr++) = i + numColumns;

      // upper right triangle
      *(itr++) = i + numColumns;
      *(itr++) = i + 1;
      *(itr++) = i + numColumns + 1;
    }
  }

  auto vid = vsg::VertexIndexDraw::create();
  vid->assignArrays(vsg::DataList{ vertices, normals, ijks, texcoords });
  vid->assignIndices(indices);
  vid->indexCount    = numIndices;
  vid->instanceCount = 1;

  // vsg::write(vid, "geometry.vsgt");

  return vid;
}

Dream3DRender::Dream3DRender(QMainWindow* QtMainWindow) : mUIMainWindow((vsgUI*)QtMainWindow) {}

Dream3DRender::~Dream3DRender() {}

vsgQt::Window* Dream3DRender::createWindow(vsg::ref_ptr<vsgQt::Viewer> viewer, vsg::ref_ptr<vsg::WindowTraits> traits, QWindow* parent,
                                           const QString& title /*= {}*/)
{
  auto window = new vsgQt::Window(viewer, traits, parent);
  // 必须设置为无边框模式，否则内部的vulkan surface 大小创建不正确，与窗口的显示模式有关系
  window->setFlags(Qt::FramelessWindowHint);
  window->setTitle(title);
  window->initializeWindow();
  if (!traits->device)
    traits->device = window->windowAdapter->getOrCreateDevice();
  return window;
}

QWidget* Dream3DRender::Initialization()
{

  QSize widgetSize(800, 600);

  auto options       = vsg::Options::create();
  options->fileCache = vsg::getEnv("VSG_FILE_CACHE");
  options->paths     = vsg::getEnvPaths("VSG_FILE_PATH");
#ifdef vsgXchange_FOUND
  options->add(vsgXchange::all::create());
#endif
  auto windowTraits = vsg::WindowTraits::create();

  auto deviceFeatures = windowTraits->deviceFeatures = vsg::DeviceFeatures::create();
  deviceFeatures->get().samplerAnisotropy            = VK_TRUE;
  deviceFeatures->get().depthClamp                   = VK_TRUE;

  windowTraits->windowTitle = "QTVulkan3DRender";

  windowTraits->width  = widgetSize.width();
  windowTraits->height = widgetSize.height();

  mViewer                    = vsgQt::Viewer::create();
  vsgQt::Window* vsgQtWindow = createWindow(mViewer, windowTraits, nullptr);
  vsgQtWindow->initializeWindow();

  if (!windowTraits->device)
    windowTraits->device = vsgQtWindow->windowAdapter->getOrCreateDevice();
  QWidget* widget = QWidget::createWindowContainer(vsgQtWindow, nullptr);
  QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  widget->setSizePolicy(sizePolicy);
  mWindow  = *vsgQtWindow;
  mDevice  = mWindow->getOrCreateDevice();
  mContext = vsg::Context::create(mDevice);

  Main_Scene          = vsg::Group::create();
  Main_SceneOpaque    = vsg::StateGroup::create();
  Main_SceneOpacity   = vsg::StateGroup::create();
  Main_SceneWireframe = vsg::StateGroup::create();

  Main_ScenePick = vsg::StateGroup::create();
  {
    vsg::dvec3 centre   = vsg::dvec3(0, 0, 0);
    double radius       = 2;
    double nearFarRatio = 0.001;
    radius              = 2;
    mlookAt             = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 0.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));
    mPicklookAt         = vsg::LookAt::create(centre + vsg::dvec3(0.0, -radius * 0.5, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));
    auto perspective    = vsg::Perspective::create(
      90.0, static_cast<double>(mWindow->extent2D().width) / static_cast<double>(mWindow->extent2D().height), mNearClipDistance, mFarClipDistance);

    mCamera = vsg::Camera::create(perspective, mlookAt, vsg::ViewportState::create(mWindow->extent2D()));

    vsg::vec4& backColor = mWindow->clearColor();
    backColor.r = backColor.g = backColor.b = 0.92;
    backColor.a                             = 1;
    main_RenderGraph                        = vsg::createCommandGraphForView(mWindow, mCamera, Main_Scene);
  }

  VkExtent2D targetExtent0 = mWindow->extent2D();
  VkExtent2D targetExtent;
  targetExtent.width  = 5;
  targetExtent.height = 5;
  {
    float fov        = 90 * vsg::PI / 180.0;
    float tga        = tan(fov / 2) * (1.0 * targetExtent.height) / targetExtent0.height;
    float atg        = atan(tga);
    float degree     = 180.0 * (atg / vsg::PI);
    auto perspective = vsg::Perspective::create(2 * degree, static_cast<double>(targetExtent.width) / static_cast<double>(targetExtent.height),
                                                mNearClipDistance, mFarClipDistance);
    mPickCamera      = vsg::Camera::create(perspective, mPicklookAt, vsg::ViewportState::create(targetExtent));
  }
  // 拾取IJK
  auto colorIJKImage = vsg::ImageInfo::create();
  // 拾取位置
  auto locationImage = vsg::ImageInfo::create();
  auto depthImage    = vsg::ImageInfo::create();

  VkFormat offscreenImageFormat = VK_FORMAT_R32G32B32A32_SFLOAT;

  auto rtt_RenderGraph = createOffscreenRendergraph(*mContext, targetExtent, *colorIJKImage, *locationImage, *depthImage, offscreenImageFormat);
  auto rtt_view        = vsg::View::create(mPickCamera, Main_ScenePick);
  rtt_RenderGraph->addChild(rtt_view);

  auto captureIJKImage    = createCaptureImage(mDevice, offscreenImageFormat, targetExtent);
  auto captureIJKCommands = createTransferCommands(mDevice, colorIJKImage->imageView->image, captureIJKImage);

  auto captureLocationImage    = createCaptureImage(mDevice, offscreenImageFormat, targetExtent);
  auto captureLocationCommands = createTransferCommands(mDevice, locationImage->imageView->image, captureLocationImage);

  Main_CommandGraph = vsg::CommandGraph::create(mWindow);
  Main_CommandGraph->addChild(rtt_RenderGraph);
  Main_CommandGraph->addChild(main_RenderGraph);
  Main_CommandGraph->addChild(captureIJKCommands);
  Main_CommandGraph->addChild(captureLocationCommands);

  mViewer->assignRecordAndSubmitTaskAndPresentation({ Main_CommandGraph });

  // add event handlers
  mViewer->setInterval(16);
  mTrackBall           = vsg::Trackball::create(mCamera);
  mTrackBall->panScale = 10;

  mViewer->addEventHandler(mTrackBall);

  mTrackBall->addKeyViewpoint(KEY_Space, LookAt::create(*mlookAt), 1.0);

  mViewer->addEventHandlers({ vsg::CloseHandler::create(mViewer) });

  mPickHandle = ScenePick::create(mUIMainWindow, mCamera, mPickCamera, mViewer, mDevice, captureIJKImage, captureLocationImage);
  mViewer->addEventHandler(mPickHandle);

  CreatePipeline();
  // compile the Vulkan objects
  mViewer->compile();

  return widget;
}

void Dream3DRender::SetTextureColorTable(QString path)
{
  updateBaseTexture(path.toStdString(), mCurrentImageBuffer, true, 1.0f);
}

void Dream3DRender::SetFiledIndexShow(int id)
{
  if (id < 0 || id >= 4)
  {
    return;
  }
  mCurrentField = id;
  if (mCurrentField > 3)
  {
    mCurrentField = 3;
  }
  uniformMyColorValue->set(vsg::vec3(mCurrentField, mAlpha, mLightSrength));
  uniformMyColorValue->dirty();
}

void Dream3DRender::SetTransparency(RenderNode& node, float alpha)
{
  mAlpha          = alpha;
  float lineAlpha = 1.0;
  if (alpha < 1.0)
  {
    // mColorBlendState->configureAttachments(true);
    // mDepthStencilState->depthWriteEnable = false;
    // mDepthStencilState->depthTestEnable  = false;
    vsg::Group::Children::iterator itFind;
    if (node.sceneNode != nullptr)
    {
      itFind = std::find(Main_SceneOpaque->children.begin(), Main_SceneOpaque->children.end(), node.sceneNode);
      if (itFind != Main_SceneOpaque->children.end())
      {
        Main_SceneOpaque->children.erase(itFind);
        Main_SceneOpacity->addChild(node.sceneNode);

        // vsg::Group::Children::iterator itFindRenderGraph;

        // itFindRenderGraph = std::find(Main_CommandGraph->children.begin(), Main_CommandGraph->children.end(), main_RenderGraph);
        // if (itFindRenderGraph != Main_CommandGraph->children.end())
        //{
        //   Main_CommandGraph->addChild(main_RenderGraphOpacity);
        // }
      }
    }
    lineAlpha = 0.5 * alpha;
  }
  else
  {
    // mColorBlendState->configureAttachments(false);
    // mDepthStencilState->depthWriteEnable = true;
    // mDepthStencilState->depthTestEnable  = true;
    vsg::Group::Children::iterator itFind;
    if (node.sceneNode != nullptr)
    {
      itFind = std::find(Main_SceneOpacity->children.begin(), Main_SceneOpacity->children.end(), node.sceneNode);
      if (itFind != Main_SceneOpacity->children.end())
      {
        Main_SceneOpacity->children.erase(itFind);
        Main_SceneOpaque->addChild(node.sceneNode);

        // vsg::Group::Children::iterator itFindRenderGraph;

        // itFindRenderGraph = std::find(Main_CommandGraph->children.begin(), Main_CommandGraph->children.end(), main_RenderGraphOpacity);
        // if (itFindRenderGraph != Main_CommandGraph->children.end())
        //{
        //   Main_CommandGraph->addChild(main_RenderGraph);
        // }
      }
    }
    lineAlpha = 1.0;
  }
  if (WireFrameShowDistance)
  {
    WireFrameShowDistance->set(vsg::vec2(mCurrentDistance, lineAlpha));
    WireFrameShowDistance->dirty();
  }
  uniformMyColorValue->set(vsg::vec3(mCurrentField, mAlpha, mLightSrength));
  uniformMyColorValue->dirty();
  mViewer->compile();
}

void Dream3DRender::SetLightSrength(double l)
{
  mLightSrength = l;
  if (mLightSrength < 0)
  {
    mLightSrength = 0;
  }
  if (mLightSrength > 5)
  {
    mLightSrength = 5.0;
  }
  uniformMyColorValue->set(vsg::vec3(mCurrentField, mAlpha, mLightSrength));
  uniformMyColorValue->dirty();
}

void Dream3DRender::SetGridLineShowDistance(RenderNode& node,float distance, vsg::vec3 color, bool bon)
{
  //if (bon)
  //{
  //  vsg::Group::Children::iterator itFind;
  //  itFind = std::find(Main_Scene->children.begin(), Main_Scene->children.end(), Main_SceneWireframe);
  //  if (itFind == Main_Scene->children.end())
  //  {
  //    Main_Scene->addChild(Main_SceneWireframe);
  //  }
  //}
  //else
  //{
  //  vsg::Group::Children::iterator itFind;
  //  itFind = std::find(Main_Scene->children.begin(), Main_Scene->children.end(), Main_SceneWireframe);
  //  if (itFind != Main_Scene->children.end())
  //  {
  //    Main_Scene->children.erase(itFind);
  //  }
  //}
  if (node.sceneNodeWireFrame)
  {
    node.sceneNodeWireFrame->SetVisible(bon);
  }
  mCurrentDistance = distance;
  if (WireFrameShowDistance)
  {
    WireFrameShowDistance->set(vsg::vec2(mCurrentDistance, mAlpha));
    WireFrameShowDistance->dirty();
  }
}

void Dream3DRender::SetVisible(RenderNode& node, bool bVisible)
{
  if (node.sceneNode == nullptr)
  {
    return;
  }
  node.sceneNode->SetVisible(bVisible);
  node.sceneNodePick->SetVisible(bVisible);
  node.sceneNodeWireFrame->SetVisible(bVisible);
  return;
  vsg::Group::Children::iterator itFind;
  if (node.sceneNode != nullptr)
  {
    itFind = std::find(Main_SceneOpaque->children.begin(), Main_SceneOpaque->children.end(), node.sceneNode);
    if (bVisible)
    {
      if (itFind == Main_SceneOpaque->children.end())
      {
        Main_SceneOpaque->addChild(node.sceneNode);
      }
    }
    else
    {
      if (itFind != Main_SceneOpaque->children.end())
      {
        Main_SceneOpaque->children.erase(itFind);
      }
    }
    itFind = std::find(Main_SceneOpacity->children.begin(), Main_SceneOpacity->children.end(), node.sceneNode);
    if (bVisible)
    {
      if (itFind == Main_SceneOpaque->children.end())
      {
        Main_SceneOpacity->addChild(node.sceneNode);
      }
    }
    else
    {
      if (itFind != Main_SceneOpacity->children.end())
      {
        Main_SceneOpacity->children.erase(itFind);
      }
    }
  }
  // MAP_RENDERNODE_REF::iterator itFindRef;
  // itFindRef = mSceneNode_RerNodes.find(node.sceneNode);
  // if (itFindRef != mSceneNode_RerNodes.end())
  {
    if (/*itFindRef->second*/ node.sceneNodePick != nullptr)
    {
      itFind = std::find(Main_ScenePick->children.begin(), Main_ScenePick->children.end(), node /*itFindRef->second*/.sceneNodePick);
      if (bVisible)
      {
        if (itFind == Main_ScenePick->children.end())
        {
          Main_ScenePick->addChild(/*itFindRef->second*/ node.sceneNodePick);
        }
      }
      else
      {
        if (itFind != Main_ScenePick->children.end())
        {
          Main_ScenePick->children.erase(itFind);
        }
      }
    }

    if (/*itFindRef->second*/ node.sceneNodeWireFrame != nullptr)
    {
      itFind = std::find(Main_SceneWireframe->children.begin(), Main_SceneWireframe->children.end(), node /*itFindRef->second*/.sceneNodeWireFrame);
      if (bVisible)
      {
        if (itFind == Main_SceneWireframe->children.end())
        {
          Main_SceneWireframe->addChild(/*itFindRef->second*/ node.sceneNodeWireFrame);
        }
      }
      else
      {
        if (itFind != Main_SceneWireframe->children.end())
        {
          Main_SceneWireframe->children.erase(itFind);
        }
      }
    }
  }
}

void Dream3DRender::HighLightShowGridCell(vsg::ivec3 ijk)
{
  if (uniformIJKValue)
  {
    uniformIJKValue->set(ijk);
    uniformIJKValue->dirty();
  }
}

void Dream3DRender::SetScale(RenderNode& node, vsg::dvec3 scale)
{
  if (node.sceneNode == nullptr)
  {
    return;
  }
  if (node.sceneNode)
  {
    vsg::ref_ptr<vsg::MatrixTransform> transform = node.sceneNode;
    transform->matrix                            = transform->transform(vsg::scale(scale));
  }

  // MAP_RENDERNODE_REF::iterator itFindRef;
  // itFindRef = mSceneNode_RerNodes.find(node.sceneNode);
  // if (itFindRef != mSceneNode_RerNodes.end())
  {
    if (/*itFindRef->second*/ node.sceneNodePick)
    {
      vsg::ref_ptr<vsg::MatrixTransform> transform = node /*itFindRef->second*/.sceneNodePick;
      transform->matrix                            = transform->transform(vsg::scale(scale));
    }
    if (/*itFindRef->second*/ node.sceneNodeWireFrame)
    {
      vsg::ref_ptr<vsg::MatrixTransform> transform = node /*itFindRef->second*/.sceneNodeWireFrame;
      transform->matrix                            = transform->transform(vsg::scale(scale));
    }
  }

  // if (DebugTransform)
  //{
  //   DebugTransform->matrix = DebugTransform->transform(vsg::scale(scale));
  // }
}

void Dream3DRender::RemoveRenderNode(RenderNode& node)
{
  if (node.sceneNode == nullptr)
  {
    return;
  }

  vsg::Group::Children::iterator itFind;
  // MAP_RENDERNODE_REF::iterator itFindRef;
  // itFindRef = mSceneNode_RerNodes.find(node.sceneNode);
  // if (itFindRef != mSceneNode_RerNodes.end())
  {
    if (node.sceneNodePick != nullptr)
    {
      itFind = std::find(Main_ScenePick->children.begin(), Main_ScenePick->children.end(), node.sceneNodePick);
      if (itFind != Main_ScenePick->children.end())
      {
        Main_ScenePick->children.erase(itFind);
      }
      // itFindRef->second.sceneNodePick->unref();
    }
    if (node.sceneNodeWireFrame != nullptr)
    {
      itFind = std::find(Main_SceneWireframe->children.begin(), Main_SceneWireframe->children.end(), node.sceneNodeWireFrame);
      if (itFind != Main_SceneWireframe->children.end())
      {
        Main_SceneWireframe->children.erase(itFind);
      }
      // itFindRef->second.sceneNodeWireFrame->unref();
    }
    // mSceneNode_RerNodes.erase(itFindRef);
  }

  itFind = std::find(Main_SceneOpaque->children.begin(), Main_SceneOpaque->children.end(), node.sceneNode);
  if (itFind != Main_SceneOpaque->children.end())
  {
    Main_SceneOpaque->children.erase(itFind);
  }
  itFind = std::find(Main_SceneOpacity->children.begin(), Main_SceneOpacity->children.end(), node.sceneNode);
  if (itFind != Main_SceneOpacity->children.end())
  {
    Main_SceneOpacity->children.erase(itFind);
  }
  // node.sceneNode->unref();
  //  node.sceneNode = nullptr;
  //  mViewer->compile();
}

void Dream3DRender::ResetScene()
{
  vsg::dvec3 centre = vsg::dvec3(0, 0, 0);
  double radius     = vsg::length(mCurrentBox.max - mCurrentBox.min) * 0.6f;
  {
    // 修改相机位置
    mlookAt->eye    = centre + vsg::dvec3(0.0, -radius * 0.05, radius * 0.8);
    mlookAt->up     = vsg::dvec3(0.0, 0.0, 1.0);
    mlookAt->center = centre;
    if (mTrackBall)
    {
      mTrackBall->addKeyViewpoint(KEY_Space, LookAt::create(*mlookAt), 1.0);
    }
  }
}

void Dream3DRender::ResetUniformBuffer()
{
  // SetTransparency(1);
  SetFiledIndexShow(0);
  HighLightShowGridCell(vsg::ivec3(-1, -1, -1));
}

void Dream3DRender::CreatePipeline()
{
  auto options       = vsg::Options::create();
  options->fileCache = vsg::getEnv("VSG_FILE_CACHE");
  options->paths     = vsg::getEnvPaths("VSG_FILE_PATH");

  auto vertexShader   = vsg::read_cast<vsg::ShaderStage>("shader/shader.vert", options);
  auto fragmentShader = vsg::read_cast<vsg::ShaderStage>("shader/shader.frag", options);

  if (!vertexShader || !fragmentShader)
  {
    return;
  }

  uint32_t numTiles = 1 * 1;

  vsg::ShaderStage::SpecializationConstants specializationContexts{
    { 0, vsg::uintValue::create(numTiles) },  // numTiles
  };

  vertexShader->specializationConstants   = specializationContexts;
  fragmentShader->specializationConstants = specializationContexts;

  // compile section
  vsg::ShaderStages stagesToCompile;
  if (vertexShader && vertexShader->module && vertexShader->module->code.empty())
    stagesToCompile.emplace_back(vertexShader);
  if (fragmentShader && fragmentShader->module && fragmentShader->module->code.empty())
    stagesToCompile.emplace_back(fragmentShader);

  // set up texture image
  std::vector<vsg::ref_ptr<vsg::ubvec4Array2D>> textureDataList;
  vsg::ref_ptr<vsg::ubvec4Array2D> updateTexture;

  mCurrentImageBuffer = updateBaseTexture("Assest/color.bmp", updateTexture, false, 1.0f);

  textureDataList.push_back(mCurrentImageBuffer);

  // set up height fields
  // std::vector<vsg::ref_ptr<vsg::floatArray2D>> heightFieldDataList;
  // for (uint32_t i = 0; i < numTiles; ++i)
  //{
  //  auto heightField = vsg::floatArray2D::create(64, 64);
  //  heightField->properties.format = VK_FORMAT_R32_SFLOAT;

  //  updateElevation(*heightField, 1.0f);
  //  heightFieldDataList.push_back(heightField);
  //}

  // set up graphics pipeline
  vsg::DescriptorSetLayoutBindings tileSettingsDescriptorBindings{
    // { binding, descriptorType, descriptorCount, stageFlags, pImmutableSamplers}
    { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }
  };

  auto tileSettingsDescriptorSetLayout = vsg::DescriptorSetLayout::create(tileSettingsDescriptorBindings);

  vsg::PushConstantRanges pushConstantRanges{
    { VK_SHADER_STAGE_VERTEX_BIT, 0,
      128 }  // projection, view, and model matrices, actual push constant calls automatically provided by the VSG's RecordTraversal
  };

  vsg::VertexInputState::Bindings vertexBindingsDescriptions{
    VkVertexInputBindingDescription{ 0, sizeof(vsg::vec3), VK_VERTEX_INPUT_RATE_VERTEX },  // vertex data
    VkVertexInputBindingDescription{ 1, sizeof(vsg::vec3), VK_VERTEX_INPUT_RATE_VERTEX },  // normal
    VkVertexInputBindingDescription{ 2, sizeof(vsg::vec3), VK_VERTEX_INPUT_RATE_VERTEX },  // ijk
    VkVertexInputBindingDescription{ 3, sizeof(vsg::vec4), VK_VERTEX_INPUT_RATE_VERTEX }   // texcoord
  };

  vsg::VertexInputState::Attributes vertexAttributeDescriptions{
    VkVertexInputAttributeDescription{ 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 },     // vertex data
    VkVertexInputAttributeDescription{ 1, 1, VK_FORMAT_R32G32B32_SFLOAT, 0 },     // normal data
    VkVertexInputAttributeDescription{ 2, 2, VK_FORMAT_R32G32B32_SFLOAT, 0 },     // ijk data
    VkVertexInputAttributeDescription{ 3, 3, VK_FORMAT_R32G32B32A32_SFLOAT, 0 },  // texcoord
  };

  vsg::ref_ptr<vsg::RasterizationState> rasterState = vsg::RasterizationState::create();
  rasterState->cullMode                             = VK_CULL_MODE_NONE;
  rasterState->lineWidth                            = 0.1;
  auto inputAssemblyState                           = vsg::InputAssemblyState::create();
  inputAssemblyState->topology                      = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST /*VK_PRIMITIVE_TOPOLOGY_LINE_LIST*/;
  mColorBlendState                                  = vsg::ColorBlendState::create();
  mDepthStencilState                                = vsg::DepthStencilState::create();
  vsg::GraphicsPipelineStates pipelineStates{ vsg::VertexInputState::create(vertexBindingsDescriptions, vertexAttributeDescriptions),
                                              inputAssemblyState,
                                              rasterState,
                                              vsg::MultisampleState::create(),
                                              mColorBlendState,
                                              mDepthStencilState };

  // 半透明的
  auto ColorBlendStateOpacity   = vsg::ColorBlendState::create();
  auto DepthStencilStateOpacity = vsg::DepthStencilState::create();
  ColorBlendStateOpacity->configureAttachments(true);
  DepthStencilStateOpacity->depthWriteEnable = false;
  DepthStencilStateOpacity->depthTestEnable  = false;
  vsg::GraphicsPipelineStates pipelineStatesOpacity{ vsg::VertexInputState::create(vertexBindingsDescriptions, vertexAttributeDescriptions),
                                                     inputAssemblyState,
                                                     rasterState,
                                                     vsg::MultisampleState::create(),
                                                     ColorBlendStateOpacity,
                                                     DepthStencilStateOpacity };

  // �Զ���uniform ���� binding = 0
  vsg::DescriptorSetLayoutBindings myColorDescriptorBindings{ // { binding, descriptorType, descriptorCount, stageFlags, pImmutableSamplers}
                                                              { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }
  };
  auto myColorDescriptorSetLayout = vsg::DescriptorSetLayout::create(myColorDescriptorBindings);

  // ������bingding����
  vsg::DescriptorSetLayoutBindings descriptorBindings{
    // { binding, descriptorType, descriptorCount, stageFlags, pImmutableSamplers}
    //{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numTiles, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
    { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numTiles, VK_SHADER_STAGE_FRAGMENT_BIT,
      nullptr }  // { binding, descriptorType, descriptorCount, stageFlags, pImmutableSamplers}
  };

  auto descriptorSetLayout = vsg::DescriptorSetLayout::create(descriptorBindings);
  // ��ɫ������ layout set = 0 set = 1  set = 2 ��˳��

  auto pipelineLayout = vsg::PipelineLayout::create(
    vsg::DescriptorSetLayouts{ descriptorSetLayout, tileSettingsDescriptorSetLayout, myColorDescriptorSetLayout }, pushConstantRanges);
  auto graphicsPipeline = vsg::GraphicsPipeline::create(pipelineLayout, vsg::ShaderStages{ vertexShader, fragmentShader }, pipelineStates);
  vsg::ref_ptr<vsg::BindGraphicsPipeline> bindGraphicsPipeline = nullptr;

  bindGraphicsPipeline = vsg::BindGraphicsPipeline::create(graphicsPipeline);

  auto graphicsPipelineOpacity =
    vsg::GraphicsPipeline::create(pipelineLayout, vsg::ShaderStages{ vertexShader, fragmentShader }, pipelineStatesOpacity);
  auto bindGraphicsPipelineOpacity = vsg::BindGraphicsPipeline::create(graphicsPipelineOpacity);

  // create texture image and associated DescriptorSets and binding
  auto clampToEdge_sampler          = vsg::Sampler::create();
  clampToEdge_sampler->addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
  clampToEdge_sampler->addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;

  vsg::ImageInfoList baseTextures;
  for (auto textureData : textureDataList)
  {
    baseTextures.push_back(vsg::ImageInfo::create(clampToEdge_sampler, textureData));
  }
  // ������������
  // auto heightFieldDescriptorImage = vsg::DescriptorImage::create(hfTextures, 0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
  auto baseDescriptorImage = vsg::DescriptorImage::create(baseTextures, 0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
  // ������
  auto descriptorSet     = vsg::DescriptorSet::create(descriptorSetLayout, vsg::Descriptors{ baseDescriptorImage });
  auto bindDescriptorSet = vsg::BindDescriptorSet::create(VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline->layout, 0, descriptorSet);

  // create StateGroup as the root of the scene/command graph to hold the GraphicsPipeline, and binding of Descriptors to decorate the whole graph
  vsg::ref_ptr<vsg::RasterizationState> rasterStatePick = vsg::RasterizationState::create();
  rasterStatePick->cullMode                             = VK_CULL_MODE_NONE;
  rasterStatePick->lineWidth                            = 0.1;
  auto inputAssemblyStatePick                           = vsg::InputAssemblyState::create();
  inputAssemblyStatePick->topology                      = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
  auto ColorBlendStatePick                              = vsg::ColorBlendState::create();
  // 拾取坐标通道，默认有一个颜色通道了
  VkPipelineColorBlendAttachmentState colorBlendAttachment = {
    VK_FALSE,                                                                                                  // blendEnable
    VK_BLEND_FACTOR_ZERO,                                                                                      // srcColorBlendFactor
    VK_BLEND_FACTOR_ZERO,                                                                                      // dstColorBlendFactor
    VK_BLEND_OP_ADD,                                                                                           // colorBlendOp
    VK_BLEND_FACTOR_ZERO,                                                                                      // srcAlphaBlendFactor
    VK_BLEND_FACTOR_ZERO,                                                                                      // dstAlphaBlendFactor
    VK_BLEND_OP_ADD,                                                                                           // alphaBlendOp
    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT  // colorWriteMask
  };
  ColorBlendStatePick->attachments.push_back(colorBlendAttachment);

  vsg::ref_ptr<vsg::DepthStencilState> depthStencilStatePick = vsg::DepthStencilState::create();

  vsg::GraphicsPipelineStates pipelineStatesPick{ vsg::VertexInputState::create(vertexBindingsDescriptions, vertexAttributeDescriptions),
                                                  inputAssemblyStatePick,
                                                  rasterStatePick,
                                                  vsg::MultisampleState::create(),
                                                  ColorBlendStatePick,
                                                  depthStencilStatePick };

  auto vertexShaderPick   = vsg::read_cast<vsg::ShaderStage>("shader/shaderPick.vert", options);
  auto fragmentShaderPick = vsg::read_cast<vsg::ShaderStage>("shader/shaderPick.frag", options);

  auto pipelineLayoutPick = vsg::PipelineLayout::create(vsg::DescriptorSetLayouts{ myColorDescriptorSetLayout }, pushConstantRanges);
  auto graphicsPipelinePick =
    vsg::GraphicsPipeline::create(pipelineLayoutPick, vsg::ShaderStages{ vertexShaderPick, fragmentShaderPick }, pipelineStatesPick);
  auto bindGraphicsPipelinePick = vsg::BindGraphicsPipeline::create(graphicsPipelinePick);

  // auto geometry = createGeometry();
  vsg::ref_ptr<vsg::MatrixTransform> transform;

  uniformMyColorValue                          = vsg::vec3Value::create(vsg::vec3(0, 1, 1));
  uniformMyColorValue->properties.dataVariance = vsg::DYNAMIC_DATA;

  uniformIJKValue                          = vsg::ivec3Value::create(vsg::ivec3(-1, -1, -1));
  uniformIJKValue->properties.dataVariance = vsg::DYNAMIC_DATA;

  // 绑定参数
  auto uniformBuffer            = vsg::DescriptorBuffer::create(uniformIJKValue, 0);
  auto uniformDescriptorSet     = vsg::DescriptorSet::create(tileSettingsDescriptorSetLayout, vsg::Descriptors{ uniformBuffer });
  auto uniformBindDescriptorSet = vsg::BindDescriptorSet::create(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, uniformDescriptorSet);

  auto uniformMyColorBuffer        = vsg::DescriptorBuffer::create(uniformMyColorValue, 0);
  auto uniformMyColorDescriptorSet = vsg::DescriptorSet::create(myColorDescriptorSetLayout, vsg::Descriptors{ uniformMyColorBuffer });
  auto uniformMyColorBindDescriptorSet =
    vsg::BindDescriptorSet::create(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 2, uniformMyColorDescriptorSet);

  Main_SceneOpaque->addChild(uniformBindDescriptorSet);
  Main_SceneOpaque->addChild(uniformMyColorBindDescriptorSet);

  // 线框的
  vsg::ref_ptr<vsg::BindGraphicsPipeline> bindGraphicsPipelineWF = nullptr;
  {
    WireFrameShowDistance                          = vsg::vec2Value::create(mCurrentDistance, 1.0);
    WireFrameShowDistance->properties.dataVariance = vsg::DYNAMIC_DATA;

    auto vertexShaderWF   = vsg::read_cast<vsg::ShaderStage>("shader/shaderWF.vert", options);
    auto fragmentShaderWF = vsg::read_cast<vsg::ShaderStage>("shader/shaderWF.frag", options);

    vsg::VertexInputState::Bindings vertexBindingsDescriptionsWF{
      VkVertexInputBindingDescription{ 0, sizeof(vsg::vec3), VK_VERTEX_INPUT_RATE_VERTEX },  // vertex data
    };

    vsg::VertexInputState::Attributes vertexAttributeDescriptionsWF{
      VkVertexInputAttributeDescription{ 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 },  // vertex data
    };

    vsg::ref_ptr<vsg::RasterizationState> rasterStateWF = vsg::RasterizationState::create();
    rasterStateWF->cullMode                             = VK_CULL_MODE_BACK_BIT;
    rasterStateWF->lineWidth                            = 2.0;
    rasterStateWF->depthBiasEnable                      = VK_TRUE;
    rasterStateWF->depthBiasConstantFactor              = 1.0;
    rasterStateWF->depthBiasSlopeFactor                 = 1.0;
    rasterStateWF->depthClampEnable                     = VK_TRUE;

    auto inputAssemblyStateWF      = vsg::InputAssemblyState::create();
    inputAssemblyStateWF->topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;

    auto ColorBlendStateWF = vsg::ColorBlendState::create();
    ColorBlendStateWF->configureAttachments(true);

    vsg::ref_ptr<vsg::DepthStencilState> depthStencilStateWF = vsg::DepthStencilState::create();

    vsg::GraphicsPipelineStates pipelineStatesWF{ vsg::VertexInputState::create(vertexBindingsDescriptionsWF, vertexAttributeDescriptionsWF),
                                                  inputAssemblyStateWF,
                                                  rasterStateWF,
                                                  vsg::MultisampleState::create(),
                                                  ColorBlendStateWF,
                                                  depthStencilStateWF };

    vsg::DescriptorSetLayoutBindings WFDistanceDescriptorBindings{ // { binding, descriptorType, descriptorCount, stageFlags, pImmutableSamplers}
                                                                   { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }
    };

    auto WFDistanceDescriptorSetLayout = vsg::DescriptorSetLayout::create(WFDistanceDescriptorBindings);

    auto pipelineLayoutWF = vsg::PipelineLayout::create(vsg::DescriptorSetLayouts{ WFDistanceDescriptorSetLayout }, pushConstantRanges);
    auto graphicsPipelineWF =
      vsg::GraphicsPipeline::create(pipelineLayoutWF, vsg::ShaderStages{ vertexShaderWF, fragmentShaderWF }, pipelineStatesWF);
    bindGraphicsPipelineWF = vsg::BindGraphicsPipeline::create(graphicsPipelineWF);

    auto uniformBufferWF            = vsg::DescriptorBuffer::create(WireFrameShowDistance, 0);
    auto uniformDescriptorSetWF     = vsg::DescriptorSet::create(WFDistanceDescriptorSetLayout, vsg::Descriptors{ uniformBufferWF });
    auto uniformBindDescriptorSetWF = vsg::BindDescriptorSet::create(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayoutWF, 0, uniformDescriptorSetWF);

    Main_SceneWireframe->addChild(uniformBindDescriptorSetWF);
  }

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindGraphicsPipeline>> bindGraphicsPipelineVisitor =
    PipelineBindVisitor<vsg::BindGraphicsPipeline>::create(bindGraphicsPipeline);
  Main_SceneOpaque->accept(*bindGraphicsPipelineVisitor);

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindGraphicsPipeline>> bindGraphicsPipelineVisitorOpacity =
    PipelineBindVisitor<vsg::BindGraphicsPipeline>::create(bindGraphicsPipelineOpacity);
  Main_SceneOpacity->accept(*bindGraphicsPipelineVisitorOpacity);

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindDescriptorSet>> bindDescriptorVisitor =
    PipelineBindVisitor<vsg::BindDescriptorSet>::create(bindDescriptorSet);
  Main_SceneOpaque->accept(*bindDescriptorVisitor);

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindDescriptorSet>> bindDescriptorVisitorOpacity =
    PipelineBindVisitor<vsg::BindDescriptorSet>::create(bindDescriptorSet);
  Main_SceneOpacity->accept(*bindDescriptorVisitorOpacity);

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindGraphicsPipeline>> bindGraphicsPipelineVisitorWF =
    PipelineBindVisitor<vsg::BindGraphicsPipeline>::create(bindGraphicsPipelineWF);
  Main_SceneWireframe->accept(*bindGraphicsPipelineVisitorWF);

  Main_Scene->addChild(Main_SceneOpaque);
  Main_Scene->addChild(Main_SceneOpacity);
  Main_Scene->addChild(Main_SceneWireframe);

  vsg::ref_ptr<PipelineBindVisitor<vsg::BindGraphicsPipeline>> bindGraphicsPipelineVisitorPick =
    PipelineBindVisitor<vsg::BindGraphicsPipeline>::create(bindGraphicsPipelinePick);
  Main_ScenePick->accept(*bindGraphicsPipelineVisitorPick);
}
RenderNode Dream3DRender::AddRenderData(RenderData* render, bool resetCamera)
{
  RenderNode outNode;
  if (render == nullptr)
  {
    return outNode;
  }
  if (render->vertices == nullptr || render->indices == nullptr)
  {
    return outNode;
  }
  ResetUniformBuffer();
  // set up vertex and index arrays
  size_t numPoints = render->vertices->size();
  if (numPoints < 1)
  {
    return outNode;
  }
  auto vid = vsg::VertexIndexDraw::create();
  vid->assignArrays(vsg::DataList{ render->vertices, render->normals, render->ijks, render->texcoords });
  vid->assignIndices(render->indices);
  vid->indexCount    = render->indices->size();
  vid->instanceCount = 1;

  // vsg::write(vid, "vid.vsgt");

  vsg::dvec3 position(static_cast<float>(0), static_cast<float>(0), 0.0f);
  auto transform     = vsg::MatrixTransform::create(vsg::translate(position));
  uint32_t tileIndex = 0;
  // auto uniformValue = vsg::uintValue::create(tileIndex);
  // auto uniformBuffer = vsg::DescriptorBuffer::create(uniformValue, 0);
  // auto uniformDescriptorSet = vsg::DescriptorSet::create(tileSettingsDescriptorSetLayout, vsg::Descriptors{ uniformBuffer });
  // auto uniformBindDescriptorSet = vsg::BindDescriptorSet::create(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, uniformDescriptorSet);
  //  //assign the tileIndex uniform directly to the transform group before the geometry
  // transform->addChild(uniformBindDescriptorSet);
  //  add geometry
  transform->addChild(vid);
  Main_SceneOpaque->addChild(transform);

  // 线框
  vsg::ref_ptr<vsg::MatrixTransform> transformWF = nullptr;
  {
    size_t countQuad                      = render->vertices->size();
    vsg::ref_ptr<vsg::intArray> indicesWF = vsg::intArray::create(8 * countQuad);
    int index                             = 0;
    for (size_t k = 0; k < countQuad; ++k)
    {
      indicesWF->at(index++) = 4 * k;
      indicesWF->at(index++) = 4 * k + 1;

      indicesWF->at(index++) = 4 * k + 1;
      indicesWF->at(index++) = 4 * k + 2;

      indicesWF->at(index++) = 4 * k + 2;
      indicesWF->at(index++) = 4 * k + 3;

      indicesWF->at(index++) = 4 * k + 3;
      indicesWF->at(index++) = 4 * k;
    }
    transformWF = vsg::MatrixTransform::create(vsg::translate(position));
    auto vidWF  = vsg::VertexIndexDraw::create();
    vidWF->assignArrays(vsg::DataList{ render->vertices });
    vidWF->assignIndices(indicesWF);
    vidWF->indexCount    = indicesWF->size();
    vidWF->instanceCount = 1;
    transformWF->addChild(vidWF);
    Main_SceneWireframe->addChild(transformWF);
  }

  vsg::ref_ptr<vsg::MatrixTransform> transformPick = vsg::MatrixTransform::create(*transform);
  Main_ScenePick->addChild(transformPick);

  vsg::ComputeBounds computeBounds;
  // Main_Scene->accept(computeBounds);
  vsg::dvec3 centre = vsg::dvec3(0, 0, 0);
  double radius     = vsg::length(render->box.max - render->box.min) * 0.6f;

  mViewer->compile();
  if (resetCamera)
  {
    // 修改相机位置
    mlookAt->eye = centre + vsg::dvec3(0.0, -radius * 0.05, radius * 0.8);
  }
  outNode.sceneNode = transform;

  // outNode.sceneNodePick = transformPick;
  // RenderNodeRefNode refNode;
  outNode.sceneNodePick      = transformPick;
  outNode.sceneNodeWireFrame = transformWF;
  // mSceneNode_RerNodes[outNode.sceneNode] = refNode;
  mCurrentBox = render->box;
  return outNode;
}

vsg::ivec3 Dream3DRender::GetPickID()
{
  if (mPickHandle != nullptr)
  {
    return mPickHandle->GetPickID();
  }
  return vsg::ivec3(-1, -1, -1);
}

void generateCylinderMesh(const vsg::vec3& P1, const vsg::vec3& P2, float radius, int segments, std::vector<vsg::vec3>& vertices,
                          std::vector<int>& indices, int offset)
{
  // 计算方向向量和长度
  vsg::vec3 axis      = { P2.x - P1.x, P2.y - P1.y, P2.z - P1.z };
  float height        = std::sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z);
  vsg::vec3 direction = normalize(axis);

  // 找到一个与方向向量垂直的基向量 (arbitrary perpendicular vector)
  vsg::vec3 up = { 0, 1, 0 };
  if (std::fabs(direction.y) > 0.99f)
  {
    up = { 1, 0, 0 };
  }
  vsg::vec3 tangent   = normalize(cross(up, direction));
  vsg::vec3 bitangent = cross(direction, tangent);

  // 计算顶面和底面圆的顶点
  for (int i = 0; i < segments; ++i)
  {
    float angle = (2.0f * vsg::PI * i) / segments;
    float cosA  = std::cos(angle);
    float sinA  = std::sin(angle);

    // 顶面顶点
    vsg::vec3 topVertex = P1 + tangent * cosA * radius + bitangent * sinA * radius;
    vertices.push_back(topVertex);

    // 底面顶点
    vsg::vec3 bottomVertex = P2 + tangent * cosA * radius + bitangent * sinA * radius;
    vertices.push_back(bottomVertex);
  }

  // 添加中心顶点（用于顶面和底面的三角扇）
  int topCenterIndex = vertices.size();
  vertices.push_back(P1);  // 顶面中心
  int bottomCenterIndex = vertices.size();
  vertices.push_back(P2);  // 底面中心

  // 构造索引：侧面
  for (int i = 0; i < segments; ++i)
  {
    int next    = (i + 1) % segments;
    int top1    = i * 2;
    int top2    = next * 2;
    int bottom1 = i * 2 + 1;
    int bottom2 = next * 2 + 1;

    // 每个分段的两个三角形构成一个四边形
    indices.push_back(top1 + offset);
    indices.push_back(bottom1 + offset);
    indices.push_back(top2 + offset);

    indices.push_back(top2 + offset);
    indices.push_back(bottom1 + offset);
    indices.push_back(bottom2 + offset);
  }

  // 构造索引：顶面
  for (int i = 0; i < segments; ++i)
  {
    int next = (i + 1) % segments;
    indices.push_back(topCenterIndex + offset);  // 顶面中心点
    indices.push_back(i * 2 + offset);           // 当前顶面点
    indices.push_back(next * 2 + offset);        // 下一个顶面点
  }

  // 构造索引：底面
  for (int i = 0; i < segments; ++i)
  {
    int next = (i + 1) % segments;
    indices.push_back(bottomCenterIndex + offset);  // 底面中心点
    indices.push_back(next * 2 + 1 + offset);       // 下一个底面点
    indices.push_back(i * 2 + 1 + offset);          // 当前底面点
  }
}
